package com.devunion.salon.server.rpc;

import com.devunion.salon.client.app.bean.ProductHistoryModel;
import com.devunion.salon.client.app.bean.ProductModel;
import com.devunion.salon.client.app.bean.search.ProductHistoryPaggingLoadConfig;
import com.devunion.salon.client.app.bean.search.ProductSearchPagingLoadConfig;
import com.devunion.salon.client.rpc.ProductService;
import com.devunion.salon.core.model.BaseProduct;
import com.devunion.salon.core.model.ProductHistory;
import com.devunion.salon.core.model.Product;
import com.devunion.salon.server.jpa.utils.ModelQueryHelper;
import com.devunion.salon.server.jpa.utils.ObjectTransformer;
import com.extjs.gxt.ui.client.data.BasePagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import org.gwtwidgets.server.spring.GWTSpringController;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.JpaTemplate;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author spetrakovsky
 */
public class ProductServiceImpl extends GWTSpringController implements ProductService {

    private JpaTemplate jpaTemplate;


    private static Object[][] PRODUCT_SEARCH_PROPERTIES = new Object[][]{
            new Object[]{"name", "barCode", "vendor"},
            new Object[]{"name", "barCode", "vendor.code"}
    };

    private static Object[][] PRODUCT_HISTORY_SEARCH_PROPERTIES = new Object[][]{
            new Object[]{"productId"},
            new Object[]{"productId"}
    };

    public PagingLoadResult<ProductModel> findProducts(final ProductSearchPagingLoadConfig config) {
        List<Product> objects = ModelQueryHelper.executeFind(jpaTemplate, config, "select p from Product p ", "p", PRODUCT_SEARCH_PROPERTIES);
        Long count = (Long) ModelQueryHelper.executeCount(jpaTemplate, config, "select count(p) from Product p ", "p", PRODUCT_SEARCH_PROPERTIES);
        List<ProductModel> result = new ArrayList<ProductModel>(objects.size());
        for (Product product : objects) {
            result.add(ObjectTransformer.translate(product));
        }
        return new BasePagingLoadResult<ProductModel>(result, config.getOffset(), count.intValue());
    }

    public ProductModel saveProduct(final ProductModel productModel) {
        final Product product = ObjectTransformer.translate(productModel);
        jpaTemplate.execute(new JpaCallback() {
            public Object doInJpa(EntityManager em) throws PersistenceException {
                em.getTransaction().begin();
                if (productModel.getId() == null) {
                    em.persist(product);
                } else {
                    createHistory(em, product.getId());
                    em.merge(product);
                }
                em.getTransaction().commit();
                return null;
            }
        });

        return ObjectTransformer.translate(product);
    }

    public PagingLoadResult<ProductHistoryModel> findProductHistory(final ProductHistoryPaggingLoadConfig config) {
        List<ProductHistory> objects = ModelQueryHelper.executeFind(jpaTemplate, config, "select p from ProductHistory p ", "p", PRODUCT_HISTORY_SEARCH_PROPERTIES);
        Long count = (Long) ModelQueryHelper.executeCount(jpaTemplate, config, "select count(p) from ProductHistory p ", "p", PRODUCT_HISTORY_SEARCH_PROPERTIES);
        List<ProductHistoryModel> result = new ArrayList<ProductHistoryModel>(objects.size());
        for (ProductHistory product : objects) {
            result.add(ObjectTransformer.translate(product));
        }
        return new BasePagingLoadResult<ProductHistoryModel>(result, config.getOffset(), count.intValue());
    }

    public void deleteProduct(Long id) {
        // TODO: may be don't delete product, just mark it to be not shown in search results.
    }

    public void createHistory(EntityManager em, Long productId) {
        Product product = em.find(Product.class, productId);
        em.persist(new ProductHistory(product));
    }

    public JpaTemplate getJpaTemplate() {
        return jpaTemplate;
    }


    public void setJpaTemplate(JpaTemplate jpaTemplate) {
        this.jpaTemplate = jpaTemplate;
    }
}